package ccm.communicate.common;

import ccm.common.*;

import java.util.ArrayList;

abstract public class Communicate implements Configurable, ReceiveDataListener
{
    protected final ArrayList<ReceiveDataListener>[] receiveDataListener;
    protected final ArrayList<StatusChangeListener> statusChangeListener;

    public Communicate()
    {
        this(1);
    }

    public Communicate(int channelNum)
    {
        receiveDataListener=new ArrayList[channelNum];
        for(int i=0;i<receiveDataListener.length;++i){receiveDataListener[i]=new ArrayList<ReceiveDataListener>();}
        statusChangeListener=new ArrayList<>();
    }

    /**
     * 启动
     */
    abstract public void start();

    /**
     * 停止
     */
    abstract public void stop();

    /**
     * 检查是否开启
     *
     * @return true表示开启
     * false表示关闭
     */
    abstract public boolean isOpen();

    /**
     * 添加一个接收数据监听器
     *
     * @param listener 监听器
     * @throws NullPointerException 监听器为null时抛出此异常
     * @implNote 默认添加到通道0
     */
    public void removeReceiveDataListener(ReceiveDataListener listener)
    {
        removeReceiveDataListener(listener,0);
    }

    /**
     * 删除一个接收数据监听器
     *
     * @param listener 监听器
     * @param channel  通道
     */
    public void removeReceiveDataListener(ReceiveDataListener listener,int channel)
    {
        if(listener==null){return;}
        if(channel<0||channel>=receiveDataListener.length){return;}
        synchronized(receiveDataListener[channel])
        {
            receiveDataListener[channel].remove(listener);
        }
    }

    /**
     * 在通道channel上调用所有的接收监听器
     *
     * @param event 事件
     */
    protected void callReceiveDataListener(ReceiveDataEvent event)
    {
        for(int i=0;i<receiveDataListener.length;++i){callReceiveDataListener(i,event);}
    }

    /**
     * 在通道channel上调用所有的接收监听器
     *
     * @param channel 通道
     * @param event   事件
     */
    protected void callReceiveDataListener(int channel,ReceiveDataEvent event)
    {
        if(channel>=0&&channel<=receiveDataListener.length)
        {
            synchronized(receiveDataListener[channel])
            {
                receiveDataListener[channel].forEach(r->
                {
                    try{r.receiveData(event);}catch(Exception e){e.printStackTrace();}
                });
            }
        }
    }

    /**
     * 添加一个接收数据监听器
     *
     * @param listener 监听器
     * @throws NullPointerException 监听器为null时抛出此异常
     * @implNote 默认添加到通道0
     */
    public void addReceiveDataListener(ReceiveDataListener listener) throws NullPointerException
    {
        addReceiveDataListener(listener,0);
    }

    /**
     * 添加一个接收数据监听器
     *
     * @param listener 监听器
     * @param channel  通道
     * @throws NullPointerException 监听器为null时抛出此异常
     */
    public void addReceiveDataListener(ReceiveDataListener listener,int channel) throws NullPointerException
    {
        if(listener==null){throw new NullPointerException();}
        if(channel<0||channel>=receiveDataListener.length){throw new NullPointerException();}
        synchronized(receiveDataListener[channel])
        {
            if(!receiveDataListener[channel].contains(listener)){receiveDataListener[channel].add(listener);}
        }
    }

    /**
     * 删除一个状态变化监听器
     *
     * @param listener 监听器
     */
    public void removeStatusChangeListener(StatusChangeListener listener)
    {
        if(listener==null){return;}
        synchronized(statusChangeListener)
        {
            statusChangeListener.remove(listener);
        }
    }

    /**
     * 添加状态变化监听器
     *
     * @param listener 监听器
     * @throws NullPointerException 监听器为null时抛出此异常
     */
    public void addStatusChangeListener(StatusChangeListener listener) throws NullPointerException
    {
        if(listener==null){throw new NullPointerException();}
        synchronized(statusChangeListener)
        {
            if(!statusChangeListener.contains(listener)){statusChangeListener.add(listener);}
        }
    }

    /**
     * 状态变化时调用监听器
     *
     * @param reason 状态变化的原因
     */
    protected void callStatusChangeListener(int reason)
    {
        callStatusChangeListener(new StatusChangeEvent(this,reason));
    }

    /**
     * 状态变化时调用监听器
     *
     * @param event 状态变化的原因
     */
    protected void callStatusChangeListener(StatusChangeEvent event)
    {
        synchronized(statusChangeListener)
        {
            statusChangeListener.forEach(r->
            {
                try{r.statusChange(event);}catch(Exception e){e.printStackTrace();}
            });
        }
    }
}
